<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\CatalogUrlRewrite\Model\Map;

use Magento\Catalog\Model\Product;
use Magento\UrlRewrite\Model\UrlFinderInterface;
use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
use Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory;

/**
 * Finds specific queried url rewrites identified by specific fields
 *
 * A group of identifiers specifies a query consumed by the client to retrieve existing url rewrites from the database
 * Clients will query a map of DatabaseMapInterface type through this class resulting into a set of url rewrites results
 * Each map type will fallback to a UrlFinderInterface by identifiers for unmapped values
 */
class UrlRewriteFinder
{
    const ENTITY_TYPE_CATEGORY = 'category';
    const ENTITY_TYPE_PRODUCT = 'product';

    /** @var DatabaseMapPool */
    private $databaseMapPool;

    /** @var UrlFinderInterface */
    private $urlFinder;

    /** @var UrlRewrite */
    private $urlRewritePrototype;

    /** @var array */
    private $urlRewriteClassNames = [];

    /**
     * @param DatabaseMapPool $databaseMapPool
     * @param UrlFinderInterface $urlFinder
     * @param UrlRewriteFactory $urlRewriteFactory
     * @param string[] $urlRewriteClassNames
     */
    public function __construct(
        DatabaseMapPool $databaseMapPool,
        UrlFinderInterface $urlFinder,
        UrlRewriteFactory $urlRewriteFactory,
        array $urlRewriteClassNames = []
    ) {
        $this->databaseMapPool = $databaseMapPool;
        $this->urlFinder = $urlFinder;
        $this->urlRewriteClassNames = $urlRewriteClassNames;
        $this->urlRewritePrototype = $urlRewriteFactory->create();
    }

    /**
     * Retrieves existing url rewrites filtered by identifiers from prebuild database maps
     * This method will fall-back to by using UrlFinderInterface when map type is not found in configured list
     *
     * @param int $entityId
     * @param int $storeId
     * @param string $entityType
     * @param int|null $rootCategoryId
     * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
     */
    public function findAllByData($entityId, $storeId, $entityType, $rootCategoryId = null)
    {
        if ($rootCategoryId
            && is_numeric($entityId)
            && is_numeric($storeId)
            && is_string($entityType)
            && isset($this->urlRewriteClassNames[$entityType])
        ) {
            $map = $this->databaseMapPool->getDataMap($this->urlRewriteClassNames[$entityType], $rootCategoryId);
            if ($map) {
                $key = $storeId . '_' . $entityId;
                return $this->arrayToUrlRewriteObject($map->getData($rootCategoryId, $key));
            }
        }

        return $this->urlFinder->findAllByData(
            [
                UrlRewrite::STORE_ID => $storeId,
                UrlRewrite::ENTITY_ID => $entityId,
                UrlRewrite::ENTITY_TYPE => $entityType
            ]
        );
    }

    /**
     * Transfers an array values to url rewrite object values
     *
     * @param array $data
     * @return UrlRewrite[]
     */
    private function arrayToUrlRewriteObject(array $data)
    {
        foreach ($data as $key => $array) {
            $data[$key] = $this->createUrlRewrite($array);
        }
        return $data;
    }

    /**
     * Creates url rewrite object and sets $data to its properties by key->value
     *
     * @param array $data
     * @return UrlRewrite
     */
    private function createUrlRewrite(array $data)
    {
        $dataObject = clone $this->urlRewritePrototype;
        $dataObject->setUrlRewriteId($data['url_rewrite_id']);
        $dataObject->setEntityType($data['entity_type']);
        $dataObject->setEntityId($data['entity_id']);
        $dataObject->setRequestPath($data['request_path']);
        $dataObject->setTargetPath($data['target_path']);
        $dataObject->setRedirectType($data['redirect_type']);
        $dataObject->setStoreId($data['store_id']);
        $dataObject->setDescription($data['description']);
        $dataObject->setIsAutogenerated($data['is_autogenerated']);
        $dataObject->setMetadata($data['metadata']);

        return $dataObject;
    }
}
